package com.vhall.component.service.inav.impl;

import com.alibaba.fastjson.JSONObject;
import com.vhall.component.entity.inav.vo.AgreeApplyReqVO;
import com.vhall.component.entity.inav.vo.ApplyReqVO;
import com.vhall.component.entity.inav.vo.CancelApplyReqVO;
import com.vhall.component.entity.inav.vo.RejectApplyReqVO;
import com.vhall.component.entity.room.dto.RoomJoinsEntityDTO;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.constant.RoomConstant;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.VssToken;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.plugin.core.enums.SendMessageTypeEnum;
import com.vhall.component.plugin.core.service.PaasService;
import com.vhall.component.service.inav.ApplyService;
import com.vhall.component.service.inav.WheatCacheService;
import com.vhall.component.service.room.RoomInnerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author yongzheng.xu
 * @date 2021/6/23 18:10
 */
@SuppressWarnings("unchecked")
@Slf4j
@Service
public class ApplyServiceImpl implements ApplyService {

    @Autowired
    private RoomInnerService roomInnerService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private PaasService paasService;

    @Autowired
    private WheatCacheService wheatCacheService;

    @Override
    public Boolean apply(ApplyReqVO reqVO, VssToken tokenInfo) {
        // 2、根据room_id和用户id查看当前房间成员中是否包含该用户。
        // 参会用户
        Integer accountId = tokenInfo.getThirdPartyUserId();
        //获取参会用户信息
        RoomJoinsEntityDTO joinUser = roomInnerService.getRoomJoinInfo(accountId, reqVO.getRoomId());
        if (null == joinUser) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        if (RoomConstant.AUDIENCE.equals(joinUser.getRoleName())) {
            Object global = redisTemplate.opsForHash().get(RedisKey.INTERACT_GLOBAL + joinUser.getRoomId(), RoomConstant.IS_HANDSUP);
            if (global == null) {
                throw new BusinessException(BizErrorCode.BIZ_NOT_SUPPORT_RAISE);
            }
        } else if (!RoomConstant.INTERACTION.equals(joinUser.getRoleName()) && !RoomConstant.ASSISTANT.equals(joinUser.getRoleName())) {
            throw new BusinessException(BizErrorCode.BIZ_ROLE_NOT_MATCH);
        }
        //申请上麦
        return apply(joinUser, "1");
    }


    @Override
    public Boolean cancelApply(CancelApplyReqVO reqVO, VssToken tokenInfo) {
        // 2、根据room_id和用户id查看当前房间成员中是否包含该用户。
        Integer accountId = tokenInfo.getThirdPartyUserId();
        //获取参会成员信息
        RoomJoinsEntityDTO joinUser = roomInnerService.getRoomJoins(accountId, reqVO.getRoomId());
        if (null == joinUser) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        //申请上麦
        return apply(joinUser, "0");
    }

    @Override
    public Boolean agreeApply(AgreeApplyReqVO reqVO, VssToken tokenInfo) {
        // 2、根据room_id和用户id查看当前房间成员中是否包含该用户。
        Integer accountId = tokenInfo.getThirdPartyUserId();
        //获取主持人参会信息
        RoomJoinsEntityDTO joinUser = roomInnerService.getRoomJoins(accountId, reqVO.getRoomId());
        if (null == joinUser) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        //获取参会人员信息
        RoomJoinsEntityDTO receiveJoinUser = roomInnerService.getRoomJoins(reqVO.getReceiveAccountId(), reqVO.getRoomId());
        if (null == receiveJoinUser) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        if (!RoomConstant.HOST.equals(joinUser.getRoleName())) {
            throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
        }
        //同意用户上麦申请
        replyApply(receiveJoinUser, "1");

        // 缓存上麦中
        wheatCacheService.cacheWaitingForWheat(receiveJoinUser.getRoomId(), receiveJoinUser.getAccountId());
        return true;
    }

    @Override
    public Boolean rejectApply(RejectApplyReqVO reqVO, VssToken tokenInfo) {
        // 2、根据room_id和用户id查看当前房间成员中是否包含该用户。
        Integer accountId = tokenInfo.getThirdPartyUserId();
        //获取主持人参会信息
        RoomJoinsEntityDTO joinUser = roomInnerService.getRoomJoins(accountId, reqVO.getRoomId());
        if (null == joinUser) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        //获取参会人员信息
        RoomJoinsEntityDTO receiveJoinUser = roomInnerService.getRoomJoins(reqVO.getReceiveAccountId(), reqVO.getRoomId());
        if (null == receiveJoinUser) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        if (!RoomConstant.HOST.equals(joinUser.getRoleName())) {
            throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
        }
        //拒绝申请上麦
        replyApply(receiveJoinUser, "0");
        return true;
    }

    /**
     * 申请上麦
     *
     * @param joinUser 申请上麦用户
     * @param type     1.申请 0.取消申请
     * @return
     */
    private Boolean apply(RoomJoinsEntityDTO joinUser, String type) {
        //缓存中获取是否已经申请上麦(1申请 2同意 3拒绝 4取消)
        String key = RedisKey.INTERACT_HANDSUP + joinUser.getAccountId();
        Object o = redisTemplate.opsForValue().get(key);
        if ("1".equals(type)) {
            //获取当前上麦用户数量
            Integer speakerCount = getSpeakerCount(joinUser);
            if (speakerCount > RoomConstant.SPEAKER_MAX_NUM) {
                throw new BusinessException(BizErrorCode.BIZ_SPEAKER_FULL);
            }
            if ("1".equals(String.valueOf(o))) {
                return false;
            }
            redisTemplate.opsForValue().set(key, 1, RoomConstant.HANDSUP_VALID_TIME, TimeUnit.SECONDS);
        } else {
            if (!"1".equals(String.valueOf(o))) {
                return false;
            }
            Long expire = redisTemplate.getExpire(key);
            assert expire != null;
            if (expire > 1) {
                redisTemplate.opsForValue().set(key, 4, RoomConstant.HANDSUP_VALID_TIME, TimeUnit.SECONDS);
            }
        }
        //获取房间信息
        RoomsEntityDTO room = roomInnerService.getRoomInfo(joinUser.getRoomId());
        JSONObject object = new JSONObject();
        object.put("type", "1".equals(type) ? SendMessageTypeEnum.VRTC_CONNECT_APPLY.getType() : SendMessageTypeEnum.VRTC_CONNECT_APPLY.getType());
        object.put("room_join_id", joinUser.getAccountId());
        //昵称
        object.put("nick_name", joinUser.getNickname());
        //用户角色（1:老师 2:学员 3:助教 4:嘉宾 5:监课）
        object.put("room_role", joinUser.getRoleName());
        //是否禁言Y是N否
        object.put("prohibit_speak", joinUser.getIsBanned());
        //是否踢出Y是N否
        object.put("kicked_out", joinUser.getIsKicked());
        //设备类型0其他1手机端2PC
        object.put("device_type", joinUser.getDeviceType());
        //设备状态0未检测1可上麦2不可上麦
        object.put("device_status", joinUser.getDeviceStatus());
        //头像
        object.put("avatar", joinUser.getAvatar());
        String body = JsonUtil.toJsonString(object);
        paasService.sendMessage(room.getChannelId(), body, null, null, null, null);
        return true;
    }

    /**
     * 同意用户上麦申请
     *
     * @param joinUser 参会用户
     * @param type     1同意 0拒绝
     */
    private void replyApply(RoomJoinsEntityDTO joinUser, String type) {
        String key = RedisKey.INTERACT_HANDSUP + joinUser.getAccountId();
        Object value = redisTemplate.opsForValue().get(key);
        RoomsEntityDTO room = roomInnerService.getRoomInfo(joinUser.getRoomId());
        JSONObject object = new JSONObject();
        object.put("room_join_id", joinUser.getAccountId());
        object.put("nick_name", joinUser.getNickname());
        object.put("room_role", joinUser.getRoleName());
        object.put("prohibit_speak", joinUser.getIsBanned());
        object.put("kicked_out", joinUser.getIsKicked());
        object.put("device_type", joinUser.getDeviceType());
        object.put("device_status", joinUser.getDeviceStatus());
        object.put("avatar", joinUser.getAvatar());
        object.put("target_id", joinUser.getAccountId());
        if ("1".equals(type)) {
            //获取当前上麦用户数量
            Integer speakerCount = getSpeakerCount(joinUser);
            if (speakerCount > RoomConstant.SPEAKER_MAX_NUM) {
                object.put("type", SendMessageTypeEnum.VRTC_CONNECT_INVITE_FULL.getType());
                String body = JSONObject.toJSONString(object);
                paasService.sendMessage(room.getChannelId(), body, null, null, null, null);
                throw new BusinessException(BizErrorCode.BIZ_SPEAKER_FULL);
            }
            if ("1".equals(String.valueOf(value))) {
                redisTemplate.opsForValue().set(key, 2, RoomConstant.HANDSUP_VALID_TIME, TimeUnit.SECONDS);
            } else {
                throw new BusinessException(BizErrorCode.BIZ_NOT_APPLY);
            }
        } else {
            if (!"1".equals(String.valueOf(value))) {
                throw new BusinessException(BizErrorCode.BIZ_NOT_APPLY);
            } else {
                Long expire = redisTemplate.getExpire(key);
                assert expire != null;
                if (expire > 1) {
                    redisTemplate.opsForValue().set(key, 3, RoomConstant.HANDSUP_VALID_TIME, TimeUnit.SECONDS);
                }
            }
        }
        object.put("type", "1".equals(type) ? SendMessageTypeEnum.VRTC_CONNECT_AGREE.getType() : SendMessageTypeEnum.VRTC_CONNECT_REFUSED.getType());
        String body = JsonUtil.toJsonString(object);
        paasService.sendMessage(room.getChannelId(), body, null, null, null, null);


    }

    /**
     * 获取上麦数量
     *
     * @param joiner 参会用户信息
     */
    private Integer getSpeakerCount(RoomJoinsEntityDTO joiner) {
        Integer result = 0;
        Map<Object, Object> speakerList = redisTemplate.opsForHash().entries(RedisKey.INTERACT_SPEAKER + joiner.getRoomId());
        int speakerCount = speakerList.size();
        Object docPermission = redisTemplate.opsForHash().get(RedisKey.INTERACT_GLOBAL + joiner.getRoomId(),
                RoomConstant.DOC_PERMISSION);
        //文档操作人
        //文档操作人没有上麦也占位置
        Boolean flag = redisTemplate.opsForHash().hasKey(RedisKey.INTERACT_SPEAKER + joiner.getRoomId(), String.valueOf(docPermission));
        if (docPermission != null && !flag && !String.valueOf(joiner.getAccountId()).equals(String.valueOf(docPermission))) {
            speakerCount++;
        }
        result = speakerCount;
        return result;
    }

}
